package com.xiaokaceng.openci.web.controller.project;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.inject.Inject;

import org.apache.commons.lang3.StringUtils;
import org.openkoala.koala.auth.ss3adapter.AuthUserUtil;
import org.openkoala.koala.exception.KoalaException;
import org.openkoala.koala.mojo.KoalaProjectCreate;
import org.openkoala.koala.pojo.MavenProject;
import org.openkoala.koala.util.ProjectParseUtil;
import org.openkoala.koala.widget.Project;
import org.openkoala.opencis.api.Developer;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import com.xiaokaceng.openci.application.DeveloperApplication;
import com.xiaokaceng.openci.application.ProjectApplication;
import com.xiaokaceng.openci.domain.CasUserConfiguration;
import com.xiaokaceng.openci.domain.ProjectDetail;
import com.xiaokaceng.openci.domain.ProjectDeveloper;
import com.xiaokaceng.openci.domain.ProjectStatus;
import com.xiaokaceng.openci.dto.ProjectDetailDto;
import com.xiaokaceng.openci.dto.ProjectDeveloperDto;
import com.xiaokaceng.openci.dto.ProjectDto;
import com.xiaokaceng.openci.dto.ProjectListDto;
import com.xiaokaceng.openci.dto.ScmConfig;
import com.xiaokaceng.openci.executor.ProjectEmailSendExecutor;
import com.xiaokaceng.openci.executor.ToolIntegrationExecutor;
import com.xiaokaceng.openci.pojo.ProjectIntegration;
import com.xiaokaceng.openci.web.FileUnpackException;
import com.xiaokaceng.openci.web.FileUploadException;
import com.xiaokaceng.openci.web.controller.BaseController;
import com.xiaokaceng.openci.web.dto.ResultDto;
import com.xiaokaceng.openci.web.dto.ResultMsgDto;
import com.xiaokaceng.openci.web.util.ZipUnPack;

@Controller
@RequestMapping("/project")
public class ProjectController extends BaseController {

	@Inject
	private ProjectApplication projectApplication;

	@Inject
	private ToolIntegrationExecutor toolIntegrationExecutor;

	@Inject
	private ProjectEmailSendExecutor projectEmailSendExecutor;
	
	@Inject
	private DeveloperApplication developerApplication;

	@ResponseBody
	@RequestMapping("/create")
	public ResultMsgDto createProject(@RequestBody ProjectDto projectDto) {
		projectDto.getProjectForCreate().setPath(getProjectSavePath());
		if (!createProjectFile(projectDto.getProjectForCreate())) {
			return ResultMsgDto.createFailure("生成Maven项目失败!");
		}
		return createProjectAndIntegrationTool(projectDto);
	}

	private ResultMsgDto createProjectAndIntegrationTool(ProjectDto projectDto) {
		if (projectApplication.isExistByName(projectDto.getProjectName())) {
			return ResultMsgDto.createFailure("项目名已被创建!");
		}
		inintProject(projectDto);
		if (projectApplication.createProject(projectDto)) {
			com.xiaokaceng.openci.domain.Project project = projectDto.getProjectForCis();
			integrateProjectToTools(project);
			return ResultMsgDto.createSuccess(String.valueOf(project.getId()));
		}
		return ResultMsgDto.createFailure("创建项目失败!");
	}

	private String getProjectSavePath() {
		return System.getProperty("java.io.tmpdir");
	}
	
	private boolean createProjectFile(org.openkoala.koala.widget.Project projectForCreate) {
		KoalaProjectCreate koalaProjectCreate = new KoalaProjectCreate();
		try {
			koalaProjectCreate.createProject(projectForCreate);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}
	
	@ResponseBody
	@RequestMapping("/import")
	public ResultDto importProject(@RequestBody ProjectDto projectDto) {
		updateProjectSaveDirName(projectDto);
		return createProjectAndIntegrationTool(projectDto);
	}

	private void updateProjectSaveDirName(ProjectDto projectDto) {
		String projectSavePath = projectDto.getImportProjectSavePath();
		if (!StringUtils.isBlank(projectSavePath)) {
			File importProjectSaveDir = new File(projectSavePath);
			String resetProjectSavePath = projectSavePath.substring(0, projectSavePath.lastIndexOf(File.separator)) + File.separator + projectDto.getProjectName();
			File resetProjectSaveDir = new File(resetProjectSavePath);
			importProjectSaveDir.renameTo(resetProjectSaveDir);
			projectDto.setImportProjectSavePath(resetProjectSavePath);
		}
	}

	private void inintProject(ProjectDto projectDto) {
		setProjectLead(projectDto);
		setCurrentUserToProjectDeveloper(projectDto);
	}
	
	private void setProjectLead(ProjectDto projectDto) {
		com.xiaokaceng.openci.domain.Project project = projectDto.getProjectForCis();
		project.setLead(AuthUserUtil.getLoginUser().getUsername());
	}

	private void setCurrentUserToProjectDeveloper(ProjectDto projectDto) {
		ProjectDeveloperDto projectDeveloperDto = new ProjectDeveloperDto();
		projectDeveloperDto.setDeveloperId(developerApplication.getByDeveloperId(AuthUserUtil.getLoginUser().getUsername()).getId());
		projectDto.getProjectDeveloperDtos().add(projectDeveloperDto);
		projectDto.configProjectDevelopers();
	}
	
	private void integrateProjectToTools(com.xiaokaceng.openci.domain.Project project) {
		ProjectDetail projectDetail = project.getProjectDetail();
		ProjectIntegration projectIntegration = new ProjectIntegration();
		projectIntegration.setGroupId(projectDetail.getGroupId());
		projectIntegration.setArtifactId(projectDetail.getArtifactId());
		projectIntegration.setProjectName(project.getName());
		projectIntegration.setTools(project.getTools());
		projectIntegration.setProjectSavePath(projectDetail.getProjectSavePath());
		projectIntegration.setDevelopers(transformDevelopers(project.getDevelopers()));
		projectIntegration.setScmConfig(getScmConfig(projectDetail));
		projectIntegration.setProjectLead(project.getLead());
		if (projectDetail.isIntegrationCas()) {
			projectIntegration.setCasUserConfiguration(CasUserConfiguration.getUniqueInstance());
		}
		toolIntegrationExecutor.execute(projectIntegration);
	}

	private ScmConfig getScmConfig(ProjectDetail projectDetail) {
		ScmConfig scmConfig = new ScmConfig();
		scmConfig.setScmType(projectDetail.getScmType());
		scmConfig.setRepositoryUrl(projectDetail.getScmRepositoryUrl());
		return scmConfig;
	}

	private Set<Developer> transformDevelopers(Set<ProjectDeveloper> projectDevelopers) {
		Set<Developer> results = new HashSet<Developer>();
		for (ProjectDeveloper each : projectDevelopers) {
			Developer developer = new Developer();
			developer.setId(each.getDeveloper().getDeveloperId());
			developer.setName(each.getDeveloper().getName());
			developer.setFullName(each.getDeveloper().getDeveloperId());
			developer.setEmail(each.getDeveloper().getEmail());
			developer.setPassword(each.getDeveloper().getPassword());
			results.add(developer);
		}
		return results;
	}

	@ResponseBody
	@RequestMapping("/generate-default-modules")
	public ProjectDto generateDefaultModules(ProjectDto projectDto) {
		Project project = projectDto.getProjectForCreate();
		project.initSSJProject();
		project.initModulePrefix(project.getAppName());
		return projectDto;
	}

	@ResponseBody
	@RequestMapping("/pagingquery")
	public List<ProjectListDto> pagingQuery(int page, int pagesize) {
		return projectApplication.pagingQueryProject(page, pagesize);
	}

	@ResponseBody
	@RequestMapping("/detail/{projectId}")
	public ProjectDetailDto getProjectDetail(@PathVariable long projectId) {
		return projectApplication.getDetailToDto(projectId);
	}

	@ResponseBody
	@RequestMapping("/is-exist/{name}")
	public boolean isExistByName(@PathVariable String name) {
		return projectApplication.isExistByName(name);
	}

	@ResponseBody
	@RequestMapping("/remove/{projectId}")
	public boolean removeProject(@PathVariable long projectId) {
		return projectApplication.remove(projectId);
	}

	@ResponseBody
	@RequestMapping(value = "/process/{projectId}", produces = "application/json;charset=UTF-8")
	public Map<String, Object> integrationProcess(@PathVariable long projectId) {
		Map<String, Object> dataMap = new HashMap<String, Object>();
		com.xiaokaceng.openci.domain.Project project = projectApplication.getDetail(projectId);
		dataMap.put("result", project.getProjectStatus().equals(ProjectStatus.INTEGRATION_TOOL));
		dataMap.put("msg", projectApplication.integrationProcess(projectId));
		return dataMap;
	}

	@ResponseBody
	@RequestMapping("/again-integeration/{projectId}")
	public boolean againIntegeration(@PathVariable long projectId) {
		projectApplication.againIntegration(projectId);
		integrateProjectToTools(projectApplication.getDetail(projectId));
		return true;
	}

	@ResponseBody
	@RequestMapping("/again-sendemail/{projectId}")
	public boolean againSendEmailToDeveloper(@PathVariable long projectId) {
		projectEmailSendExecutor.execute(projectApplication.getDetail(projectId));
		return true;
	}

	@ResponseBody
	@RequestMapping(value = "/upload", method = RequestMethod.POST)
	public String uploadMavenProject(@RequestParam("file") CommonsMultipartFile file) {
		try {
			String fileName = file.getOriginalFilename();
			String fileSavePath = getFileSavePath(String.valueOf(new Date().getTime()));
			String filePullPath = fileSavePath + File.separator + fileName;
			saveToFileSystem(file, filePullPath);
			return filePullPath;
		} catch (FileUploadException e) {
			return "";
		}
	}

	@ResponseBody
	@RequestMapping("/resolve")
	public Map<String, Object> resolveMavenProject(String fileName) {
		Map<String, Object> dataMap = new HashMap<String, Object>();
		try {
			String fileSavePath = fileName.substring(0, fileName.lastIndexOf(File.separator) + 1);
			unpackFile(fileName, fileSavePath);
			dataMap.put("fileSavePath", fileName.substring(0, fileName.lastIndexOf(".")));
			
			MavenProject project = ProjectParseUtil.parseProject(getPomFilePath(fileName));
			packagingReturnParsms(dataMap, project);
		} catch (KoalaException e) {
			dataMap.put("msg", "解析pom文件失败!");
		} catch (FileUnpackException e) {
			dataMap.put("msg", "解压文件失败!");
		}
		return dataMap;
	}
	
	private void packagingReturnParsms(Map<String, Object> dataMap, MavenProject project) {
		dataMap.put("name", project.getName());
		dataMap.put("groupId", project.getGroupId());
		dataMap.put("artifactId", project.getArtifactId());
		dataMap.put("version", project.getVersion());
	}

	private String getPomFilePath(String fileName) {
		return fileName.substring(0, fileName.lastIndexOf("."));
	}

	private void unpackFile(String filePath, String toDir) {
		try {
			ZipUnPack.upZipFile(filePath, toDir);
		} catch (Exception e) {
			throw new FileUnpackException(e);
		}
	}

	private void saveToFileSystem(CommonsMultipartFile file, String fileSavePath) {
		File newFile = new File(fileSavePath);
		try {
			file.transferTo(newFile);
		} catch (IllegalStateException e) {
			throw new FileUploadException(e);
		} catch (IOException e) {
			throw new FileUploadException(e);
		}
	}

	private String getFileSavePath(String timestamp) {
		String savePath = System.getProperty("java.io.tmpdir") + File.separator + timestamp;
		File file = new File(savePath);
		file.mkdir();
		return savePath;
	}

}
